#include <bits/stdc++.h>
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;

char ibuf[1<<24],*iptr=ibuf;
inline static int read(){
    int sum=0,ch=*iptr++;
    while(!isdigit(ch)) ch=*iptr++;
    while(isdigit(ch)) sum=sum*10+(ch^48),ch=*iptr++;
    return sum;
}

/*
第一次独立切主题库黑题，纪念一下

感觉纯代数不好想，先想想这玩意的几何意义是什么样子的。可以想象每个点到原点框出若干个长方体，你选的点要满足在三视图中都没有落在长方形里。
所以第一个想法诞生了：把每个长方体变成三个顶到边界的长方体，然后做长方体体积并。三维体积并看上去就做不了，但是这里的长方体其实是有特殊性质的。
从上往下扫描，可以发现每次操作的都是一个前缀且不存在删除操作，因此可以直接用吉司机线段树维护取 max 操作
额上面的分析好像有点肤浅，更具体的，扫到的那个图形最开始是原来的上视图，然后随着扫描线往下，每次会把前缀的行和列填满，因此好像甚至可以做到线性

上面是弱化版（CF815D）的分析，我们继续来看看这题
拓展到三维之后，因为想象不了（至少我想象不出来）四维的情况，所以考虑四维在三维的投影
考虑对第四维做扫描线，每次计算三维体积并，那么在最开始（d 为极大值）就和弱化版的情况完全一致（每个合法点不能有两维被同一个人偏序）
然后随着扫描线往下扫，每次会把没有三维偏序某个长方体的点全部干掉（因为此时的合法点已经在第四维被该长方体超过）
这一点反映在弱化版的扫描线上就是把扫描线到 z<=a[i].z 之后的过程直接裁掉（此时的所有点一定有两维被偏序），然后把 a[i].z 赋值为 n
其实我感觉想到这里已经有点把路走窄了，但是好像还是能做。我们把扫描线每一段的贡献离线下来，于是可以维护出外层扫描线每次对答案的增量（但很不好写）

所以是扫描线套扫描线，甚至依然是线性的，太帅了
*/

int n,m,cnt[500005]; struct{int x,y,z,t;}a[500005],b[500005];
uint val[500005],pre[500005],vp[500005],vq[500005];
uint s1[500005],s2[500005],s3[500005],pr1[500005],pr2[500005];
// 空间常数疑似有点过于大了
struct Dat{
    int p,q,M,t,z;
    operator uint()const{
        return t*((uint)(m-M)*(m-p)-(p<q?val[q]-val[p]-(uint)M*(q-p):0));
    }
}c[500005];
signed main(){
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    fread(ibuf,1,1<<24,stdin),n=read(),m=read(); uint ans=0;
    for(int i=1,x,y,z;i<=n;val[x]=max((int)val[x],y),i++)
        x=read(),y=read(),z=read(),a[i]={x,y,z,read()},cnt[a[i].z]++;
    
    for(int i=m;i;i--) val[i]=max(val[i],val[i+1]); for(int i=1;i<=m;i++) val[i]+=val[i-1];
    for(int i=m;i;i--) cnt[i]+=cnt[i+1]; for(int i=1;i<=n;i++) b[cnt[a[i].z]--]=a[i];
    
    for(int i=1,p=0,q=m,M=0,t;i<=n;i++){
        p=max(p,b[i].x),M=max(M,b[i].y); while(q && val[q]-val[q-1]<=M) q--;
        pre[i]=ans+=c[i]={p,q,M,t=b[i].z-b[i+1].z,b[i+1].z};
        vp[i]=vp[i-1]+val[p]*t,vq[i]=vq[i-1]+val[q]*t;
        pr1[i]=pr1[i-1]+(m-M)*t,pr2[i]=pr2[i-1]+(m-p)*t;
        s1[i]=s1[i-1]+(q-p)*t,s2[i]=s2[i-1]+M*q*t,s3[i]=s3[i-1]+t*M;
    } memset(cnt+1,0,4*m),ans+=*c={0,m,0,m-b[1].z,b[1].z},c->p=c->q=-1;
    for(int i=1;i<=n;i++) cnt[b[i].t]++; for(int i=m;i;i--) cnt[i]+=cnt[i+1];
    for(int i=1;i<=n;i++) a[cnt[b[i].t]--]=b[i]; ans*=(m-a[1].t);
    // for(int i=1;i<=n;i++) debug("%d %d %d %d\n",a[i].x,a[i].y,a[i].z,a[i].t);
    // ptr: 最后一个满足 p<q 的位置， lim: 最后一个没被填满的位置   | 拆贡献拆吐了
    
    // t*((uint)(m-c)*(m-p)-(p<q?val[q]-val[p]-(uint)c*(q-p):0))
    for(int i=1,p=0,q=m,M=0,p1=1,p2=1,l,r,lim=m,ptr=m;i<=n;i++){
        p=max(p,a[i].x),M=max(M,a[i].y); while(c[lim].z<a[i].z) lim--;
        while(q && val[q]-val[q-1]<=M) q--; ptr=min(ptr,lim);
        while(p1<=lim && c[p1].p<p) c[p1++].p=-1; p1=min(p1,lim+1);
        while(p2<=lim && c[p2].M<M) c[p2++].q=-1; p2=min(p2,lim+1);
        while(~ptr && (ptr<p1?p:c[ptr].p)>=(ptr<p2?q:c[ptr].q)) ptr--;
        uint sum=pre[lim]-pre[max(p1,p2)-1]+Dat{p,q,M,m-c[min(p1,p2)-1].z};
        
        // if(p1<p2) for(int i=p1;i<p2;i++) c[i].q=q,c[i].M=M,sum+=c[i];
        // if(p2<p1) for(int i=p2;i<p1;i++) c[i].p=p,sum+=c[i];
        if(p1<p2){
            l=p1-1,r=min(ptr,p2-1);
            if(~ptr) sum+=-val[q]*(c[l].z-c[r].z)+vp[r]-vp[l]+M*(s1[r]-s1[l]); // -val[q]+val[p]+M*(q-p);
            sum+=(m-M)*(pr2[p2-1]-pr2[l]); // (m-M)*(m-p);
        }
        if(p2<p1){
            l=p2-1,r=min(ptr,p1-1);
            if(~ptr) sum+=-vq[r]+vq[l]+val[p]*(c[l].z-c[r].z)+s2[r]-s2[l]-(s3[r]-s3[l])*p; // -val[q]+val[p]+M*q-M*p;
            sum+=(pr1[p1-1]-pr1[l])*(m-p); // (m-M)*(m-p);
            
            // uint qwq=t,awa=0;
            // for(int i=p2;i<p1;i++){
            //     qwq-=p<c[i].q?c[i].t:0;
            //     if((p<c[i].q)!=(i<=ptr)){
            //         debug("%d %d %d %d\n",p,c[i].q,i,ptr);
            //         abort();
            //     }
            //     sum+=c[i].t*(
            //         (m-c[i].M)*(m-p)
            //         -(p<c[i].q?val[c[i].q]-val[p]-c[i].M*(c[i].q-p):0)
            //     );
            // } assert(!qwq);
        }
        
        ans+=sum*(a[i].t-a[i+1].t);
    } printf("%u\n",ans);
}